package com.sj.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.sj.common.dto.auth.RegParam;
import com.sj.common.dto.auth.SendCodeParam;
import com.sj.common.lang.ApiResult;
import com.sj.common.lang.Const;
import com.sj.entity.Role;
import com.sj.entity.User;
import com.sj.entity.UserRole;
import com.sj.service.RoleService;
import com.sj.service.UserRoleService;
import com.sj.service.UserService;
import com.sj.utils.RedisUtils;
import com.sj.utils.ValidateCodeUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Created with IntelliJ IDEA.
 * User: xiaoqi
 * Date: 2022-03-10
 * Time: 下午 23:11
 * Description: 认证模块
 *
 * @author xiaoqi
 * @since 2022-03-10
 */
@RestController
@Api(tags = "认证模块")
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private ValidateCodeUtil validateCodeUtil;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private UserRoleService userRoleService;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Value("${know.third-part.qq-login-flag}")
    private String qqLoginFlagKey;

    @ApiOperation("设置qq登录状态")
    @GetMapping("/qq/login/flag")
    public ApiResult setQQLoginFlag(@RequestParam Integer id) {
        redisUtils.set(qqLoginFlagKey + Const.COLON + id, true, 15);
        return ApiResult.success("设置成功");
    }

    @ApiOperation("判断qq是否登录成功")
    @GetMapping("/qq/login/check")
    public ApiResult checkQQLogin(@RequestParam Integer id) {
        Object o = redisUtils.get(qqLoginFlagKey + Const.COLON + id);
        boolean result = false;
        if(o != null){
            result = Boolean.parseBoolean(o.toString());
        }
        return ApiResult.success("判断是否登录成功", result);
    }

    @GetMapping("/captcha")
    @ApiOperation("发送图片验证码")
    public ApiResult captcha() {
        String key = UUID.randomUUID().toString();
        Map<Object, Object> map = validateCodeUtil.getRandomCodeBase64();
        String image = String.valueOf(map.get("image"));
        String code = String.valueOf(map.get("code"));
        String pre = "data:image/png;base64,";
        image = pre + image;
        redisUtils.hset(Const.CAPTCHA_KEY, key, code, 120);
        return ApiResult.success(
                MapUtil.builder()
                        .put("key", key)
                        .put("image", image)
                        .put("code", code)
                        .build()
        );
    }

    @PostMapping("/register")
    @ApiOperation("注册")
    public ApiResult register(@RequestBody @Validated RegParam regParam) {
        if (!regParam.getPassword().equals(regParam.getRpassword())) {
            return ApiResult.error("两次密码不一致");
        }
        User user = new User();
        BeanUtil.copyProperties(regParam, user, "code", "rpassword");

        // 首先判断手机号或用户名时候被注册
        List<User> list = userService.lambdaQuery().eq(User::getUsername, regParam.getUsername()).list();
        if (list.size() > 0) {
            return ApiResult.error("该用户名已被注册，换一个试试吧");
        }
        list = userService.lambdaQuery().eq(User::getPhone, regParam.getPhone()).list();
        if (list.size() > 0) {
            return ApiResult.error("该手机号已被注册，换一个试试吧");
        }

        // 判断用户是否获取验证码
        String codeKey = Const.CAPTCHA_KEY + regParam.getUsername() + regParam.getPhone();
        if (!redisUtils.hasKey(codeKey)) {
            return ApiResult.error("请先获取验证码");
        }

        // 判断验证码是否正确
        if (!StrUtil.equals(regParam.getCode(), String.valueOf(redisUtils.get(codeKey)))) {
            return ApiResult.error("验证码不正确");
        }
        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        boolean result = userService.save(user);
        user.setPassword(null);
        if (result) {
            // 添加普通用户角色
            Role one = roleService.lambdaQuery().eq(Role::getCode, Const.USER).one();
            UserRole build = UserRole.builder().userId(user.getId()).roleId(one.getId()).build();
            userRoleService.save(build);
            // 删除redis中的当前验证码
            redisUtils.del(codeKey);
            return ApiResult.success("注册成功", user);
        }

        return ApiResult.error("注册失败");
    }

    @PostMapping("/send-code")
    @ApiOperation("发送数字验证码")
    public ApiResult sendCode(@RequestBody @Validated SendCodeParam sendCodeParam) {
        // 首先判断 redis中时候有该用户和手机号的验证码
        String codeKey = Const.CAPTCHA_KEY + sendCodeParam.getUsername() + sendCodeParam.getPhone();
        if (redisUtils.hasKey(codeKey)) {
            return ApiResult.success("验证码三分钟内有效" + redisUtils.get(codeKey));
        }
        // 如果没有 首先生成验证码
        Integer random = NumberUtil.generateRandomNumber(1000, 9000, 1)[0];
        // 存到redis 两分钟后过期
        redisUtils.set(codeKey, random, 60 * 3);
        return ApiResult.success("您的验证码为：" + random);
    }
}